package com.wjy.game;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;

/**
 * 服务器端
 *
 * @author Administrator
 */
@Slf4j
public class Server extends Thread {

    /**
     * 客户端socket
     */
    Socket clientSocket;

    /**
     * 客户端数据哈希表
     */
    final Hashtable<Object, Object> clientDataHash;

    /**
     * 客户端名称哈希表
     */
    final Hashtable<Object, String> clientNameHash;

    /**
     * 客户端颜色哈希表
     */
    Hashtable<Object, String> clientColorHash;

    /**
     * 房间占位标识
     */
    final String[] inChess;

    /**
     * 房间号数组
     */
    int[] roomNum;

    /**
     * 消息面板
     */
    MessageBoard board;

    /**
     * 客户端是否关闭
     */
    boolean isClientClosed = false;

    public Server(Socket clientSocket, Hashtable<Object, Object> clientDataHash,
        Hashtable<Object, String> clientNameHash, int[] roomNum, String[] inChess, MessageBoard board,
        Hashtable<Object, String> clientColorHash) {
        this.clientSocket = clientSocket;
        this.clientDataHash = clientDataHash;
        this.clientNameHash = clientNameHash;
        this.inChess = inChess;
        this.roomNum = roomNum;
        this.board = board;
        this.clientColorHash = clientColorHash;
    }

    /**
     * 服务器响应
     * 
     * @param feedbackString
     */
    public void feedback(String feedbackString) {
        synchronized (clientDataHash) {
            DataOutputStream outData = (DataOutputStream)clientDataHash.get(clientSocket);
            try {
                outData.writeUTF(feedbackString);
            } catch (Exception e) {
                log.error("向客户端发送数据发生异常，异常信息：{}", e.getMessage(), e);
            }
        }

    }

    /**
     * 获取时间
     * @return
     */
    public String getDate() {
        DateFormat df = new SimpleDateFormat("HH:mm:ss");
        return df.format(new Date());
    }

    /**
     * 获取哈希表的键
     * @param targetHash
     * @param hashValue
     * @return
     */
    public Object getHashKey(Hashtable targetHash, Object hashValue) {
        Object hashKey;
        for (Map.Entry entry : (Set<Map.Entry>)targetHash.entrySet()) {
            Object value = entry.getValue();
            if (hashValue.equals(value)) {
                return (entry.getKey());
            }
        }
        return null;
    }

    /**
     * 获取房间列表
     * @return
     */
    public String getRoomList() {
        String roomList = Arrays.stream(inChess).filter(inFlag -> !"0".equals(inFlag)).collect(Collectors.joining(" "));
        /*StringBuilder roomList = new StringBuilder();
        for (int i = 0; i < 50; i++) {
            if (!Objects.equals(inChess[i], "0")) {
                roomList.append(" ").append(inChess[i]);
            }
        }*/
        return "LIST_ROOM " + roomList;
    }

    /**
     * 消息转换
     * @param message
     */
    public void messageTransfer(String message) {
        String clientName = new String();
        String peerName = new String();
        board.getMessageBoard().append(message);
        // if (message.startsWith("/")) {
        if (message.startsWith("SEND_NAME")) {
                clientName = message.substring(10);
                clientNameHash.put(clientSocket, clientName);
            } else if (message.equals("LIST_ROOM")) {
                log.info("房间数：{}", roomNum[0]);
                for (int i = 0; i < roomNum[0]; i++) {
                    log.info("{}{}", roomNum[0], inChess[i]);
                }
                feedback(getRoomList());
            } else if (message.startsWith("CREATE_ROOM")) {
                String chessServerName = message.substring(12);
                synchronized (clientNameHash) {
                    clientNameHash.put((Object)clientSocket, message.substring(12));
                }
                synchronized (inChess) {
                    inChess[roomNum[0]] = "1-" + chessServerName;
                    roomNum[0] += 1;
                }
            } else if (message.startsWith("JOIN_ROOM")) {
                String serverName, selfName;
                String[] getName = message.split(" ");
                serverName = getName[1];
                selfName = getName[2];
                boolean IsOk = false;
                for (int i = 0; i < roomNum[0]; i++) {
                    String[] getTemp = inChess[i].split("-");
                    if (getTemp[0].equals("1") && getTemp[1].equals(serverName)) {
                        IsOk = true;
                        break;
                    }
                }
                if (IsOk) {
                    synchronized (inChess) {
                        for (int i = 0; i < roomNum[0]; i++) {
                            String[] getTemp = inChess[i].split("-");
                            if (getTemp[0].equals("1") && getTemp[1].equals(serverName)) {
                                inChess[i] = "2-" + serverName + "-" + selfName;
                                break;
                            }
                        }
                    }
                    chessPeerTalk(serverName, ("JOIN_OK " + selfName));
                    feedback("JOIN_OK " + serverName);
                    synchronized (inChess) {
                        boolean isNeed = false;
                        for (int i = 0; i < roomNum[0]; i++) {
                            String[] getTemp = inChess[i].split("-");
                            if (getTemp[0].equals("1") && getTemp[1].equals(selfName)) {
                                inChess[i] = inChess[i + 1];
                                isNeed = true;
                            }
                        }
                        if (isNeed) {
                            inChess[roomNum[0]] = "0";
                            roomNum[0]--;
                        }
                    }

                } else {
                    chessPeerTalk(selfName, "REJECT");
                    try {
                        clientClose();
                    } catch (Exception ez) {
                    }
                }
            } else if (message.startsWith("TALK")) {
                String[] info = message.split(" ");
                peerName = info[1];
                String message1 = "";
                for (int i = 2; i < info.length; i++) {
                    message1 += info[i];
                }
                chessPeerTalk(peerName, "TALK " + (String)clientNameHash.get(clientSocket) + " " + message1);
            } else if (message.startsWith("GIVE_UP")) {
                if (message.startsWith("GIVE_UP_NO_START")) {
                    String chessClientName = message.substring(9);
                    synchronized (inChess) {
                        String status = "0";
                        for (int i = 0; i < roomNum[0]; i++) {
                            String[] getTemp = inChess[i].split("-");
                            if ("1".equals(getTemp[0]) && getTemp[1].equals(chessClientName)) {
                                status = "1-" + i;
                            }
                        }
                        if (status.startsWith("1")) {
                            String[] info = status.split("-");
                            for (int i = Integer.parseInt(info[1]); i < roomNum[0]; i++) {
                                inChess[i] = inChess[i + 1];
                            }
                            inChess[roomNum[0]] = "0";
                            roomNum[0]--;
                        }
                    }
                }
                if (message.startsWith("GIVE_UP_IN_GAME")) {
                    String chessClientName = message.substring(9);
                    String[] getTemp = null;
                    int IsOk = -1;
                    for (int i = 0; i < roomNum[0]; i++) {
                        getTemp = inChess[i].split("-");
                        if (getTemp[0].equals("2") && getTemp[1].equals(chessClientName)) {
                            IsOk = 2;
                            break;
                        }
                        if (getTemp[0].equals("2") && getTemp[2].equals(chessClientName)) {
                            IsOk = 1;
                            break;
                        }
                    }
                    if (IsOk != -1) {
                        chessPeerTalk(getTemp[IsOk], "WIN");
                        synchronized (inChess) {
                            for (int i = 0; i < roomNum[0]; i++) {
                                String[] getTemp1 = inChess[i].split("-");
                                if (getTemp[0].equals("2")
                                    && (getTemp1[1].equals(chessClientName) || getTemp1[2].equals(chessClientName))) {
                                    if (roomNum[0] < 49) {
                                        inChess[i] = inChess[i + 1];
                                    }
                                }
                            }
                            inChess[roomNum[0] - 1] = "0";
                            roomNum[0]--;
                        }
                    }
                }
            } else if (message.startsWith("START_GAME ")) {
                String[] getColorName = message.split(" ");
                clientName = getColorName[1];
                log.info("客户名" + clientName + " 颜色" + getColorName[2] + "房间数" + roomNum[0]);
                clientColorHash.put((Object)clientSocket, getColorName[2]);
                for (int i = 0; i < roomNum[0]; i++) {
                    String[] getTemp = inChess[i].split("-");
                    log.info(" ：：：" + getTemp[0] + ">" + getTemp[1] + ">" + getTemp[2]);
                    if (getTemp[0].equals("2") && (getTemp[1].equals(clientName) || getTemp[2].equals(clientName))) {
                        {
                            if (getTemp[1].equals(clientName)) {
                                String colorName = (String)clientColorHash.get(getHashKey(clientNameHash, getTemp[2]));
                                if (colorName.equals("-1")) {
                                    log.info("房主：Dadasd");
                                    feedback("WAIT");
                                } else {
                                    log.info("房主：dadada");
                                    feedback("READY " + colorName);
                                    chessPeerTalk(getTemp[2], "FIRST " + colorName);
                                }
                            }
                            if (getTemp[2].equals(clientName)) {
                                String colorName = (String)clientColorHash.get(getHashKey(clientNameHash, getTemp[1]));
                                if (colorName.equals("-1")) {
                                    log.info("费房主：dasda");
                                    feedback("WAIT");
                                } else {
                                    feedback("READY " + colorName);
                                    log.info("费房主：dasda非");
                                    chessPeerTalk(getTemp[1], "FIRST " + colorName);
                                }
                            }
                        }
                    }
                }
            } else if (message.startsWith("FAIL")) {
                String[] getInfo = message.split(" ");
                chessPeerTalk(getInfo[1], "FAIL");
                synchronized (clientColorHash) {
                    String clientName1 = (String)clientNameHash.get(clientSocket);
                    for (int i = 0; i < roomNum[0]; i++) {
                        String[] getTemp1 = inChess[i].split("-");
                        if (getTemp1[0].equals("2")
                            && (getTemp1[1].equals(clientName1) || getTemp1[2].equals(clientName1))) {
                            {
                                clientColorHash.put((Object)getHashKey(clientNameHash, getTemp1[1]), "-1");
                                clientColorHash.put((Object)getHashKey(clientNameHash, getTemp1[2]), "-1");
                            }
                        }
                    }
                }
                synchronized (inChess) {
                    String clientName1 = (String)clientNameHash.get(clientSocket);
                    for (int i = 0; i < roomNum[0]; i++) {
                        String[] getTemp1 = inChess[i].split("-");
                        if (getTemp1[0].equals("2")
                            && (getTemp1[1].equals(clientName1) || getTemp1[2].equals(clientName1))) {
                            if (roomNum[0] < 49) {
                                inChess[i] = inChess[i + 1];
                            }
                        }
                    }
                    inChess[roomNum[0] - 1] = "0";
                    roomNum[0]--;
                }
            } else if (message.startsWith("CHESS")) {
                String[] getInfo = message.split(" ");
                chessPeerTalk(getInfo[1], message);
            } else if (message.startsWith("TAKE_BACK ")) {
                chessPeerTalk(message.substring(10), message);
            } else if (message.startsWith("REFUSE_BACK")) {
                chessPeerTalk(message.substring(11), "REFUSE_BACK");
            } else if (message.startsWith("AGREE_BACK")) {
                chessPeerTalk(message.substring(11), "AGREE_BACK");
            } else {
                /*feedback("REJECT 发送无效！");
                return;*/
                message = getDate() + clientNameHash.get(clientSocket) + ":" + message;
                board.getMessageBoard().append(message + "\n");
                board.getMessageBoard().setCaretPosition(board.getMessageBoard().getText().length());
            }

            /*} else {
                message = getDate() + clientNameHash.get(clientSocket) + ":" + message;
                board.getMessageBoard().append(message + "\n");
                board.getMessageBoard().setCaretPosition(board.getMessageBoard().getText().length());
            }*/
    }

    /**
     * 棋手交流
     * @param chessPeerTalk
     * @param chessTalkMessage
     * @return
     */
    public boolean chessPeerTalk(String chessPeerTalk, String chessTalkMessage) {

        for (Enumeration enu = clientDataHash.keys(); enu.hasMoreElements();) {
            Socket userClient = (Socket)enu.nextElement();

            if (chessPeerTalk.equals(clientNameHash.get(userClient))
                && !chessPeerTalk.equals(clientNameHash.get(clientSocket))) {
                synchronized (clientDataHash) {
                    DataOutputStream peerOutData = (DataOutputStream)clientDataHash.get(userClient);
                    try {
                        peerOutData.writeUTF(chessTalkMessage);
                    } catch (IOException es) {
                        es.printStackTrace();
                    }
                }
                return false;
            }
        }
        return true;
    }

    public void firstCome() {
        feedback("连接服务器成功！");
    }

    public void clientClose() {
        board.getMessageBoard().append("用户断开:" + clientSocket + "\n");

        synchronized (inChess) {
            String clientName = clientNameHash.get(clientSocket);
            String status = "0";
            for (int i = 0; i < roomNum[0]; i++) {
                String[] getTemp = inChess[i].split("-");
                if ("1".equals(getTemp[0]) && getTemp[1].equals(clientName)) {
                    status = "1-" + i;
                }
                if ("2".equals(getTemp[0]) && (getTemp[1].equals(clientName) || getTemp[2] == clientName)) {
                    status = "2-" + i;
                }
            }
            if (status.startsWith("1")) {
                String[] info = status.split("-");
                for (int i = Integer.parseInt(info[1]); i < roomNum[0]; i++) {
                    inChess[i] = inChess[i + 1];
                }
                inChess[roomNum[0]] = "0";
                roomNum[0]--;
            }
            if (status.startsWith("2")) {
                messageTransfer("GIVE_UP_IN_GAME " + clientName);
            }
        }
        synchronized (clientDataHash) {
            clientDataHash.remove(clientSocket);
        }
        synchronized (clientNameHash) {
            clientNameHash.remove(clientSocket);
        }
        board.getStatusLabel().setText("当前连接数:" + clientDataHash.size());
        try {
            clientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        isClientClosed = true;
    }

    @Override
    public void run() {
        DataInputStream inData;
        synchronized (clientDataHash) {
            board.getStatusLabel().setText("当前连接数:" + clientDataHash.size());
        }
        try {
            inData = new DataInputStream(clientSocket.getInputStream());
            firstCome();
            while (true) {
                String message = inData.readUTF();
                messageTransfer(message);
            }
        } catch (IOException esx) {

        } finally {
            if (!isClientClosed) {
                clientClose();
            }
        }
    }
}
